package com.teradata.olingo.metadata.core.edm.mapper.impl;

import com.teradata.olingo.metadata.core.edm.mapper.api.*;
import com.teradata.olingo.metadata.core.edm.mapper.exception.ODataGenericModelException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


final class GenericAssociationPathImpl implements GenericAssociationPath {
  private final String alias;
  private final List<GenericElement> pathElements;
  private final IntermediateStructuredType sourceType;
  private final IntermediateStructuredType targetType;
  private final List<IntermediateJoinColumn> joinColumns;
  private final boolean isCollection;
  private final GenericAssociationAttribute partner;
  private final IntermediateJoinTable joinTable;

  GenericAssociationPathImpl(final IntermediateNavigationProperty association,
                             final IntermediateStructuredType source) throws ODataGenericModelException {

    final List<GenericElement> pathElementsBuffer = new ArrayList<>();
    pathElementsBuffer.add(association);

    alias = association.getExternalName();
    this.sourceType = source;
    this.targetType = (IntermediateStructuredType) association.getTargetEntity();
    this.joinColumns = association.getJoinColumns();
    this.pathElements = Collections.unmodifiableList(pathElementsBuffer);
    this.isCollection = association.isCollection();
    this.partner = association.getPartner();
    this.joinTable = (IntermediateJoinTable) association.getJoinTable();
  }

  GenericAssociationPathImpl(final GenericEdmNameBuilder namebuilder, final GenericAssociationPath associationPath,
                             final IntermediateStructuredType source, final List<IntermediateJoinColumn> joinColumns,
                             final GenericAttribute attribute) {

    final List<GenericElement> pathElementsBuffer = new ArrayList<>();
    pathElementsBuffer.add(attribute);
    pathElementsBuffer.addAll(associationPath.getPath());

    alias = namebuilder.buildNaviPropertyBindingName(associationPath, attribute);
    this.sourceType = source;
    this.targetType = (IntermediateStructuredType) associationPath.getTargetType();
    if (joinColumns.isEmpty())
      this.joinColumns = ((GenericAssociationPathImpl) associationPath).getJoinColumns();
    else
      this.joinColumns = joinColumns;
    this.pathElements = Collections.unmodifiableList(pathElementsBuffer);
    this.isCollection = associationPath.isCollection();
    this.partner = associationPath.getPartner();
    this.joinTable = (IntermediateJoinTable) associationPath.getJoinTable();
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getAlias()
   */
  @Override
  public String getAlias() {
    return alias;
  }

  @Override
  public List<GenericPath> getInverseLeftJoinColumnsList() throws ODataGenericModelException {
    final List<GenericPath> result = new ArrayList<>();
    for (final IntermediateJoinColumn column : this.joinTable.buildInverseJoinColumns()) {
      result.add(targetType.getPathByDBField(column.getName()));
    }
    return result;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getJoinColumnsList()
   */
  @Override
  public List<GenericOnConditionItem> getJoinColumnsList() throws ODataGenericModelException {
    final List<GenericOnConditionItem> result = new ArrayList<>();
    /*for (final IntermediateJoinColumn column : this.joinColumns) {
      // ManyToOne
      if (cardinality == PersistentAttributeType.MANY_TO_ONE
          || cardinality == PersistentAttributeType.MANY_TO_MANY)
        result.add(new GenericOnConditionItemImpl(
            sourceType.getPathByDBField(column.getName()),
            targetType.getPathByDBField(column.getReferencedColumnName())));
      else
        result.add(new GenericOnConditionItemImpl(
            sourceType.getPathByDBField(column.getReferencedColumnName()),
            targetType.getPathByDBField(column.getName())));
    }*/
    return result;
  }

  @Override
  public GenericJoinTable getJoinTable() {
    return joinTable;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getLeaf()
   */
  @Override
  public GenericAssociationAttribute getLeaf() {
    return (GenericAssociationAttribute) pathElements.get(pathElements.size() - 1);
  }

  @Override
  public List<GenericPath> getLeftColumnsList() throws ODataGenericModelException {
    final List<GenericPath> result = new ArrayList<>();
    /*for (final IntermediateJoinColumn column : this.joinColumns) {
      // ManyToOne
      if (joinTable != null
          || (cardinality == PersistentAttributeType.MANY_TO_ONE))
        result.add(sourceType.getPathByDBField(column.getName()));
      else
        result.add(sourceType.getPathByDBField(column.getReferencedColumnName()));
    }*/
    return result;
  }

  @Override
  public GenericAssociationAttribute getPartner() {
    return partner;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getPath()
   */
  @Override
  public List<GenericElement> getPath() {
    return pathElements;
  }

  @Override
  public List<GenericPath> getRightColumnsList() throws ODataGenericModelException {
    final List<GenericPath> result = new ArrayList<>();
    /*for (final IntermediateJoinColumn column : this.joinColumns) {
      // ManyToOne
      if (cardinality == PersistentAttributeType.MANY_TO_ONE)
        result.add(targetType.getPathByDBField(column.getReferencedColumnName()));
      else
        result.add(targetType.getPathByDBField(column.getName()));
    }*/
    return result;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getSourceType()
   */
  @Override
  public GenericStructuredType getSourceType() {
    return sourceType;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#getTargetType()
   */
  @Override
  public GenericStructuredType getTargetType() {
    return targetType;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.GenericAssociationPath#isCollection()
   */
  @Override
  public boolean isCollection() {
    return isCollection;
  }

  @Override
  public String toString() {
    return "GenericAssociationPathImpl [alias=" + alias + ", pathElements=" + pathElements + ", sourceType=" + sourceType
        + ", targetType=" + targetType + ", joinColumns=" + joinColumns //+ ", cardinality=" + cardinality
        + ", joinTable=" + joinTable + "]";
  }

  /*private PersistentAttributeType getCardinality() {
    return cardinality;
  }*/

  private List<IntermediateJoinColumn> getJoinColumns() {
    return joinColumns;
  }

}
